#include "FileUtil.h"

#include <sys/stat.h>
#include <sys/types.h>
#include <memory>
#include <stdio.h>
#include <stdio.h> 

#include "Util.h"

#ifdef _WINDOWS
#include <direct.h>
#include <objbase.h>
#include <strsafe.h>
#include <io.h>
#else
#include "dirent.h"
#include <unistd.h>
#endif

#ifndef F_OK
#define F_OK 4
#endif

using namespace renderengine;
using namespace std;

bool FileUtil::exists(const std::string& filePath) {
    if (filePath.empty())
        return false;
    return access(filePath.c_str(), F_OK) == 0;
}

std::string FileUtil::getFileName(const std::string& filePath, bool withoutExt) {
    std::string result = "";
    if (!filePath.empty()) {
        size_t index = filePath.find_last_of('/');
        if (index != string::npos) {
            result = filePath.substr(index + 1);
        }
        else {
            result = filePath;
        }

        if (withoutExt) {
            index = result.find_last_of('.');
            if (index != string::npos) {
                result = result.substr(0, index);
            }
        }
    }

    return result;
}

std::string FileUtil::getFileDir(const std::string& filePath) {
    std::string result = "";
    if (!filePath.empty()) {
        size_t index = filePath.find_last_of('/');
#ifdef _WINDOWS
        size_t index2 = filePath.find_last_of('\\');
        if (index2 != std::string::npos)
            index = index == std::string::npos ? index2 : max(index, index2);
#endif
        if (index != string::npos) {
            result = filePath.substr(0, index);
        }
    }

    return result;
}

std::string FileUtil::getFileExt(const std::string& filePath) {
    size_t lastDot = filePath.find_last_of('.');
    return lastDot == string::npos ? string() : filePath.substr(lastDot);
}

std::string FileUtil::renameFileExt(const std::string& filePath, const std::string& ext) {
    size_t lastDot = filePath.find_last_of('.');
    if (lastDot != string::npos) {
        return filePath.substr(0, lastDot) + ext;
    }
    else {
        return filePath + ext;
    }
}

std::fstream* FileUtil::openFile(const std::string& path, std::ios_base::openmode mode) {
#ifdef _WINDOWS
    wstring utf16 = Util::toUtf16(path);
    return new fstream(utf16.c_str(), mode);
#else
    return new fstream(path.c_str(), mode);
#endif
}

std::string FileUtil::getFileContent(const std::string& filePath) {
    if (!exists(filePath))
        return "";

    std::shared_ptr<fstream> ifs(openFile(filePath, ios::in));
    ifs->seekg(0, ios::end);
    int fileLen = (int)ifs->tellg();
    char* contents = new char[fileLen + 1];
    ifs->seekg(0, ios::beg);
    ifs->read(contents, fileLen);
    contents[fileLen] = '\0';
    ifs->close();

    string result(contents);
    delete[] contents;

    return result;
}

size_t FileUtil::getFileSize(const std::string& filePath) {
#ifdef _WINDOWS
    struct _stat sb;
    wstring utf16 = Util::toUtf16(filePath);
    if (_wstat(utf16.c_str(), &sb) == 0)
        return sb.st_size;
#else
    struct stat sb;
    if (stat(filePath.c_str(), &sb) == 0)
        return sb.st_size;
#endif

    return 0;
}

std::string FileUtil::combineFilePath(const std::string& folder, const std::string& fileName) {
    size_t localFolderLen = folder.length();

    if (folder[localFolderLen - 1] != '\\' || folder[localFolderLen - 1] != '/') {
#ifdef _WINDOWS
        return folder + '\\' + fileName;
#else
        return folder + '/' + fileName;
#endif

    }
    else {
        return folder + fileName;
    }
}
